// Created by lvyer on 2021/11/18.

// 1、动态注册 JNI函数
// 2、封装OpenGL工具类
// 3、着色器代码文件加载
// 4、C++实例保留（指针操作）
#include <jni.h>
#include <tools/LogTools.h>
#include <tools/JNITools.h>
#include <TextureRenderer.h>

#define NATIVE_JNI_CLASS_NAME "com/bytecodezz/app/learn2/NativeRenderer"

extern "C"
JNIEXPORT jlong JNICALL nativeJNIInitRenderer(JNIEnv *env, jobject thiz) {
    LOGD("nativeJNIInitRenderer");
    TextureRenderer *textureRenderer = new TextureRenderer();
    textureRenderer->init();
    return reinterpret_cast<jlong>(textureRenderer);
}

extern "C"
JNIEXPORT void JNICALL nativeJNIInsertImageData(JNIEnv *env, jobject thiz,
                                                jlong ptr, jint format, jint width,
                                                jint height, jbyteArray data) {
    LOGD("nativeJNIInsertImageData");
    TextureRenderer *textureRenderer = reinterpret_cast<TextureRenderer *>(ptr);
    int len = env->GetArrayLength(data);
    uint8_t *buf = new uint8_t[len];
    env->GetByteArrayRegion(data, 0, len, reinterpret_cast<jbyte *>(buf));
    textureRenderer->setImageData(format, width, height, buf);
    delete[] buf;
    env->DeleteLocalRef(data);
}

extern "C"
JNIEXPORT void JNICALL
nativeJNISurfaceChange(JNIEnv *env, jobject thiz, jlong ptr, jint width, jint height) {
    LOGD("nativeJNISurfaceChange");
    TextureRenderer *textureRenderer = reinterpret_cast<TextureRenderer *>(ptr);
    textureRenderer->onSurfaceChanged(width, height);

}

extern "C"
JNIEXPORT void JNICALL nativeJNIDraw(JNIEnv *env, jobject thiz, jlong ptr) {
    LOGD("nativeJNIDraw");
    TextureRenderer *textureRenderer = reinterpret_cast<TextureRenderer *>(ptr);
    textureRenderer->draw();
}

//{"方法名字符串","方法签名字符串",对应C层方法签名},
//{"native_Init","()V",(void *)(nativeInit)} 表示java层的方法名叫native_Init，无参数，void返回值，对应c层的方法为nativeInit(...)
static JNINativeMethod dynamicJniMethods[] = {
        {"nativeInitRenderer",    "()J",       (void *) nativeJNIInitRenderer},
        {"nativeInsertImageData", "(JIII[B)V", (void *) nativeJNIInsertImageData},
        {"nativeSurfaceChange",   "(JII)V",    (void *) nativeJNISurfaceChange},
        {"nativeDraw",            "(J)V",      (void *) nativeJNIDraw}
};

//加载lib库的时候首先被回调的方法
extern "C" jint JNI_OnLoad(JavaVM *vm, void *reserved) {
    LOGD("JNI_OnLoad");
    JNIEnv *env = nullptr;
    //生成 jni环境变量
    if (vm->GetEnv(reinterpret_cast<void **>(&env), JNI_VERSION_1_6) != JNI_OK) {
        return JNI_ERR;
    }
    //注册JNI函数
    jint regState = JNITools::registerNativeMethods(env, NATIVE_JNI_CLASS_NAME, dynamicJniMethods,
                                                    sizeof(dynamicJniMethods) /
                                                    sizeof(dynamicJniMethods[0]));
    if (regState != JNI_TRUE) {
        return JNI_ERR;
    }
    LOGD("JNI_OnLoad end");
    return JNI_VERSION_1_6;
}

extern "C" void JNI_OnUnload(JavaVM *vm, void *reserved) {
    JNIEnv *env = nullptr;
    if (vm->GetEnv(reinterpret_cast<void **>(&env), JNI_VERSION_1_6) != JNI_OK) {
        return;
    }
    //注销 JNI函数
    JNITools::unRegisterNativeMethods(env, NATIVE_JNI_CLASS_NAME);
}
